/*
 * $Id: tio_put.c,v 1.2 2005-12-26 07:41:48 bacon Exp $
 */

#include <xp/bas/tio.h>
#include <xp/bas/locale.h>
#include <xp/bas/errno.h>

xp_ssize_t xp_tio_putc (xp_tio_t* tio, xp_char_t c)
{
#ifndef XP_CHAR_IS_MCHAR
	xp_size_t n, i;
	xp_mchar_t mc[50];
#endif

	if (tio->outbuf_len >= xp_countof(tio->outbuf)) {
		/* maybe, previous flush operation has failed a few 
		 * times previously. so the buffer is full.
		 */
		tio->errnum = XP_TIO_ENOSPC;	
		xp_seterrno (XP_ENOBUFS);
		return -1;
	}

#ifdef XP_CHAR_IS_MCHAR
	tio->outbuf[tio->outbuf_len++] = c;	
	if (tio->outbuf_len >= xp_countof(tio->outbuf))
		return xp_tio_flush (tio);
#else

	n = xp_wctomc (c, mc, xp_countof(mc));
	if (n == 0) {
		tio->errnum = XP_TIO_EILSEQ;
		return -1;
	}

	for (i = 0; i < n; i++) {
		tio->outbuf[tio->outbuf_len++] = mc[i];
		if (tio->outbuf_len >= xp_countof(tio->outbuf)) {
			if (xp_tio_flush(tio) == -1) return -1;
		}
	}		
#endif

	if (c == XP_CHAR('\n') && tio->outbuf_len > 0) {
		if (xp_tio_flush(tio) == -1) return -1;
	}

	return 1;
}

xp_ssize_t xp_tio_puts (xp_tio_t* tio, const xp_char_t* str)
{
	xp_ssize_t n;
	const xp_char_t* p;

	for (p = str; *p != XP_CHAR('\0'); p++) {
		n = xp_tio_putc (tio, *p);
		if (n == -1) return -1;
		if (n == 0) break;
	}

	return p - str;
}

xp_ssize_t xp_tio_putsx (xp_tio_t* tio, const xp_char_t* str, xp_size_t size)
{
	xp_ssize_t n;
	const xp_char_t* p, * end;

	if (size == 0) return 0;

	p = str; end = str + size;
	while (p < end) {
		n = xp_tio_putc (tio, *p);
		if (n == -1) return -1;
		if (n == 0) break;

		p++;
	}

	return p - str;
}

xp_ssize_t xp_tio_putsn (xp_tio_t* tio, ...)
{
	xp_ssize_t n;
	xp_va_list ap;

	xp_va_start (ap, tio);
	n = xp_tio_putsv (tio, ap);
	xp_va_end (ap);

	return n;
}

xp_ssize_t xp_tio_putsxn (xp_tio_t* tio, ...)
{
	xp_ssize_t n;
	xp_va_list ap;

	xp_va_start (ap, tio);
	n = xp_tio_putsxv (tio, ap);
	xp_va_end (ap);

	return n;
}

xp_ssize_t xp_tio_putsv (xp_tio_t* tio, xp_va_list ap)
{
	const xp_char_t* p;
	xp_size_t n, total = 0;

	while ((p = xp_va_arg (ap, const xp_char_t*)) != XP_NULL) {
		if (p[0] == XP_CHAR('\0')) continue;

		n = xp_tio_puts (tio, p);
		if (n == -1) return -1;
		if (n == 0) break;

		total += n;
	}

	return total;
}

xp_ssize_t xp_tio_putsxv (xp_tio_t* tio, xp_va_list ap)
{
	const xp_char_t* p;
	xp_size_t len, n, total = 0;

	while ((p = xp_va_arg (ap, const xp_char_t*)) != XP_NULL) {
		len = xp_va_arg (ap, xp_size_t);
		if (len == 0) continue;

		n = xp_tio_putsx (tio, p, len);
		if (n == -1) return -1;
		if (n == 0) break;

		total += n;
	}

	return total;
}
